#include "AlienGenIO.h"

int AlienGenIO::sendBuffer(const char* buffer, unsigned int *size)
{
    char *b = (char *)buffer;
    char *end = b + *size;
    int n;
    while(b < end) {
        *size = end-b;
        n = send( _socket, b, *size, 0);
        if(n == -1)
            return -1;
        if(!n)
            return 0;
        b += n;
    }

    return 0;
}

char * AlienGenIO::receiveBuffer(unsigned int* size)
{
    unsigned int bufSize = _buffer_size;
    char buffer[_buffer_size];
    int s = 0;

    char *b = NULL;
    char *ret = new char[1];
    *ret = 0;
    unsigned int totalSize = 0;

    fd_set readfds;
    FD_ZERO(&readfds);
    FD_SET(_socket, &readfds);

    if(_timeout != 0)
    {
        struct timeval timeOut = { _timeout, 0};
        int rc;
        if((rc = select((int)_socket+1, &readfds, NULL, NULL, &timeOut)) <= 0) {
            return NULL;
        }
    }
    else
    {
        int rc;
        if((rc = select((int)_socket+1, &readfds, NULL, NULL, NULL)) <= 0) {
            return NULL;
        }
    }

    if (!FD_ISSET(_socket, &readfds)) {
        *size = 0;
        return NULL;
    }

    do
    {
        struct timeval timeOut = { 0, 100};
        int rc;
        if((rc = select((int)_socket+1, &readfds, NULL, NULL, &timeOut)) <= 0) {
            break;
        }

        s = recv(_socket, buffer, bufSize, 0);
        if(s < 0) {
            delete [] b;
            *size = 0;
            return NULL;
        }

        if(s == 0) break;

        if(!b) {
            b = new char[s+1];
            memcpy(b, buffer, s);
            *(b+s) = '\0';
        }
        else {
            char *t = new char[totalSize + s + 1];
            memcpy(t, b, totalSize);
            delete [] b;
            b = t;
            t += totalSize;
            memcpy(t, buffer, s);
            *(t+s) = '\0';
        }
        totalSize += s;
    } while(1); // While select works !

    *size = totalSize;

    return b;
}

int AlienGenIO::putInt(int s)
{
    char b[4];
    b[0] = (s & 0xFF);
    b[1] = ((s >> 8) & 0xFF);
    b[2] = ((s >> 16) & 0xFF);
    b[3] = ((s >> 24) & 0xFF);
    int n;
    n = send(_socket, b, 4, MSG_NOSIGNAL);
    if(n != 4)
    {
        return -1;
    }

    return 0;
}
int AlienGenIO::getIntNew(void )
{
    char b[4];
    int s=0;
    s = recv(_socket, b, 4, 0);
    if(s < 4) {

        return -1;
    }


    s = ((b[3] & 0xFF) << 24) |
        ((b[2] & 0xFF) << 16) |
        ((b[1] & 0xFF) << 8) |
        (b[0] & 0xFF);

    return s;
}
int AlienGenIO::getInt(void )
{
    char b[4];
    int s = 0;

    fd_set readfds;
    FD_ZERO(&readfds);
    FD_SET(_socket, &readfds);

    struct timeval timeOut = { _timeout, 0};

    int rc;
    if((rc = select((int)_socket+1, &readfds, NULL, NULL, &timeOut)) <= 0) {
        printf("select !");
        return -1;
    }

    if (!FD_ISSET(_socket, &readfds)) {
        //throw new Exception();
        printf("FD_ISSET !");
        return -1;
    }

    s = recv(_socket, b, 4, 0);
    if(s < 4) {
        printf("recv");
        return -1;
    }

    s = ((b[3] & 0xFF) << 24) |
        ((b[2] & 0xFF) << 16) |
        ((b[1] & 0xFF) << 8) |
        (b[0] & 0xFF);

    return s;
}

int AlienGenIO::putString(char* str, unsigned int* size)
{
    if(this->putInt(*size) != 0)
    {
        return -1;
    }

    if(this->sendBuffer(str, size) != 0)
    {
        return -1;
    }

    return 0;
}

char* AlienGenIO::getString(unsigned int *size)
{
    *size = this->getInt();

    char* buffer = (char*)malloc(sizeof(char)*(*size));
  //  char* buffer = NULL;
    int s = 0;

    fd_set readfds;
    FD_ZERO(&readfds);
    FD_SET(_socket, &readfds);

    if(_timeout != 0)
    {
        struct timeval timeOut = { _timeout, 0};
        int rc;
        if((rc = select((int)_socket+1, &readfds, NULL, NULL, &timeOut)) <= 0) {
            delete buffer;
            *size = 0;
            return NULL;
        }
    }
    else
    {
        int rc;
        if((rc = select((int)_socket+1, &readfds, NULL, NULL, NULL)) <= 0) {
            delete buffer;
            *size = 0;
            return NULL;
        }
    }

    if (!FD_ISSET(_socket, &readfds)) {
        delete buffer;
        *size = 0;
        return NULL;
    }

    struct timeval timeOut = { 0, 100};
    int rc;
    if((rc = select((int)_socket+1, &readfds, NULL, NULL, &timeOut)) <= 0) {
        delete buffer;
        *size = 0;
        return NULL;
    }

    s = recv(_socket, buffer, *size, 0);
    if(s <= 0) {
        delete buffer;
        *size = 0;
        return NULL;
    }

    *size = s;
    return buffer;
}

